package com.universal.aysncCompose.controller;

import com.universal.entity.UniversalPost;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * CompletableFuture异步编排
 *
 * @author: austin
 * @date: 2022/10/30 23:29
 */
@Slf4j
@RestController
@RequestMapping("/api")
public class CompletableFutureCompose {

    //1. 文章内容信息 2s
    //2. 作者相关信息 1s 依赖于1的查询结果
    //3. 文章评论信息 1s 依赖于1的查询结果
    //4. 文章分类信息 1s 依赖于1的查询结果
    //5. 文章专栏信息 1s 依赖于1的查询结果
    //6. 相关文章信息 1s 依赖于1的查询结果
    //...

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Resource
    private ExecutorService executorService;

    @SneakyThrows
    @GetMapping("/asyncGetReturnPost")
    public UniversalPost asyncGetReturnPost() {
        UniversalPost post = new UniversalPost();
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        CompletableFuture<UniversalPost> postContentFuture = CompletableFuture.supplyAsync(() -> {
            try {
                post.setId(1L);
                post.setContent("全球boot项目中心帖子内容...");
                log.info("专栏帖子内容信息...");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return post;
        }, executorService);

        CompletableFuture<Void> authorFuture = postContentFuture.thenAcceptAsync((res) -> {
            try {
                res.setAuthor(res.getId() + "全球boot项目中心帖子【作者】...");
                log.info("专栏作者信息...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, executorService);

        CompletableFuture<Void> commentFuture = postContentFuture.thenAcceptAsync((res) -> {
            try {
                res.setComment(res.getId() + "全球boot项目中心帖子【评论】...");
                log.info("专栏评论信息...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, executorService);

        CompletableFuture<Void> categoryFuture = postContentFuture.thenAcceptAsync((res) -> {
            try {
                res.setCategory(res.getId() + "全球boot项目中心帖子【分类】...");
                log.info("获取分类信息...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, threadPoolTaskExecutor);

        CompletableFuture<Void> columnFuture = postContentFuture.thenAcceptAsync((res) -> {
            try {
                res.setColumn(res.getId() + "全球boot项目中心帖子【专栏】...");
                log.info("专栏分类信息...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, threadPoolTaskExecutor);

        CompletableFuture<Void> recommendFuture = postContentFuture.thenAcceptAsync((res) -> {
            try {
                res.setRecommend(res.getId() + "全球boot项目中心帖子【推荐】...");
                log.info("专栏推荐信息...");
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, threadPoolTaskExecutor);

        CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(postContentFuture, authorFuture, commentFuture, categoryFuture, columnFuture, recommendFuture);
        CompletableFuture<String> result = allOfFuture.thenApply(res -> {
            log.info("all future is done...");
            return "这是一个结果";
        });

        //上面所有future执行完成需要6s，假设get时间只设置3秒，当所有的任务没在3秒内执行完成，get会抛出TimeoutException异常
        log.info("result: {}", result.get());


        //同步执行的话耗时大概是：2+1+1+1+1+1=7s

        stopWatch.stop();
        log.info("asyncGetReturnPost耗时: {} ms", stopWatch.getTotalTimeMillis());
        return post;
    }

    private static void thenCombineMethod() {
        CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("cf1");
            return "hello";
        });
        CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("cf2");
            return "world";
        });
        CompletableFuture<String> future = cf1.thenCombine(cf2, (r1, r2) -> r1 + " " + r2);
        try {
            log.info("cf1&cf2都执行完成...");
            System.out.println(future.get(3, TimeUnit.SECONDS));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        thenCombineMethod();
    }
}
